package com.analyse.stock.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.analyse.stock.constant.ApiConstant;
import com.analyse.stock.constant.StockConstant;
import com.analyse.stock.enums.MarketEnum;
import com.analyse.stock.form.PickStockQueryForm;
import com.analyse.stock.mapper.StockInfoMapper;
import com.analyse.stock.model.StockCoreInfoModel;
import com.analyse.stock.model.StockInfoModel;
import com.analyse.stock.service.IStockInfo;
import com.analyse.stock.utils.HttpUtil;
import com.analyse.stock.utils.StockStringUtil;
import com.analyse.stock.vo.BoardVO;
import com.analyse.stock.vo.FinanceDataVO;
import com.analyse.stock.vo.PickStockVO;
import com.analyse.stock.vo.TickerVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StockInfoService extends ServiceImpl<StockInfoMapper, StockInfoModel> implements IStockInfo {

    @Override
    public StockInfoModel getStockInfo(String stockCode) {
        if(StringUtils.isBlank(stockCode)){
            return null;
        }
        LambdaQueryWrapper<StockInfoModel> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StockInfoModel::getActive,1);
        if(StringUtils.isNotBlank(stockCode) && !"all".equalsIgnoreCase(stockCode)){
            wrapper.eq(StockInfoModel::getStockCode,stockCode);
        }
        List<StockInfoModel> list = super.list(wrapper);
        if(CollUtil.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }
    @Override
    public List<StockInfoModel> getStockList(Set<String> stockCodes) {
        LambdaQueryWrapper<StockInfoModel> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StockInfoModel::getActive,1);
        wrapper.in(StockInfoModel::getExchangeCode,Sets.newHashSet("XSHE","XSHG"));
        if(CollUtil.isNotEmpty(stockCodes)){
            wrapper.in(StockInfoModel::getStockCode,stockCodes);
        }
        return super.list(wrapper);
    }

    @Override
    public Integer pullStockList(String countryCode) {
        MarketEnum[]  marketEnums = MarketEnum.values();
        AtomicInteger num = new AtomicInteger(0);
        for(MarketEnum marketEnum : marketEnums){
            String url = StrUtil.format(ApiConstant.STOCK_LIST_URL,marketEnum.name());
            String result = HttpUtil.sendGet(url,"*/*", StockConstant.UTF8,6000L);
            if(StringUtils.isBlank(result)){
                continue;
            }
            JSONObject jsonObject = JSONObject.parseObject(result);
            if(jsonObject.getInteger("code") != 200 || Objects.isNull(jsonObject.getJSONArray("data"))){
                continue;
            }
            List<TickerVO> list = JSONObject.parseArray(jsonObject.getString("data"), TickerVO.class);
            List<StockInfoModel> list2 = list.stream().map(StockInfoModel::transStockInfoModel).collect(Collectors.toList());
            super.saveBatch(list2);
            num.getAndAdd(list2.size());
        }
        return num.get();
    }

    @Override
    public Integer update(String stockCodes) {
        AtomicInteger num = new AtomicInteger(0);
        Set<String> sets = Sets.newHashSet();
        if(StringUtils.isNotBlank(stockCodes)){
            sets.addAll(Arrays.asList(stockCodes.split(StrUtil.COMMA)));
        }
        List<StockInfoModel> list = this.getStockList(sets);
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        Date currentDate = DateUtil.date();
        for (StockInfoModel model : list) {
            long time = System.currentTimeMillis()*1001;
            try{
                String secid = String.format("%s.%s", model.getMarkCode(), model.getStockCode());
                String url = StrUtil.format(ApiConstant.STOCK_MV_URL, secid,time);
                String result = HttpUtil.sendGet(url, "application/javascript", StockConstant.UTF8, 6000L);
                if (StringUtils.isBlank(result)) {
                    continue;
                }
                JSONObject object = JSON.parseObject(result);
                FinanceDataVO dataVO = StockStringUtil.getObject(object.getString("data"), FinanceDataVO.class);
                model.setCapitalStock(StockStringUtil.getDecimalValue(dataVO.getF84()));
                model.setTradeCapitalStock(StockStringUtil.getDecimalValue(dataVO.getF85()));
                model.setPbRate(StockStringUtil.getDecimalValue(dataVO.getF167()));
                model.setMarkValue(StockStringUtil.getDecimalValue(dataVO.getF116()));
                model.setTradeMv(StockStringUtil.getDecimalValue(dataVO.getF117()));
                if(StringUtils.isNotBlank(dataVO.getF189())){
                    model.setUpMarketDate(DateUtil.parse(dataVO.getF189(), DatePattern.PURE_DATE_FORMAT));
                }
                model.setUpdateTime(currentDate);

                String secuCode = String.format("%s.%s",model.getStockCode(), model.getShortMarkCode());
                String stockBoardUrl = StrUtil.format(ApiConstant.STOCK_BOARD_URL, secuCode);

                //个股的板块（地域板块，行业板块，题材）
                this.pullBoardData(model,stockBoardUrl,1);

                //个股所属的概念板块
                String stockConceptBoardUrl = StrUtil.format(ApiConstant.STOCK_CONCEPT_BOARD_URL, secuCode);
                this.pullBoardData(model,stockConceptBoardUrl,2);

                model.setDataPullDate(currentDate);
                this.baseMapper.updateById(model);
                log.info("### 股票：{}，{}, 更新财务数据, 总市值：{}，流通市值：{} ###",
                        model.getStockName(),model.getStockCode(),model.getMarkValue(),model.getTradeMv());
                num.getAndAdd(1);
            }catch (Exception ex){
                log.error("### 股票：{}，{}, 财务数据异常：{},error:{}",
                        model.getStockName(),model.getStockCode(),ex.getMessage(),ex);
            }
        }
        return num.get();
    }

    @Override
    public List<PickStockVO> pickStock(PickStockQueryForm queryForm) {
        return baseMapper.pickStock(queryForm);
    }

    //个股的板块（地域板块，行业板块，题材）
    private void pullBoardData(StockInfoModel model,String url,Integer dataType) {
        String stockBoardResult = HttpUtil.sendGet(url, "text/plain", StockConstant.UTF8, 6000L);
        if (StringUtils.isBlank(stockBoardResult)) {
            return;
        }
        log.info("## 股票：{}-{}， 返回所属板块：{}",model.getStockName(),model.getStockCode(),stockBoardResult);
        JSONObject object1 = JSON.parseObject(stockBoardResult);
        if(object1.getInteger("code") != 0 || Objects.isNull(object1.getJSONObject("result"))
                || object1.getJSONObject("result").getInteger("count")<1){
            return;
        }
        List<BoardVO> array = JSONObject.parseArray(object1.getJSONObject("result").getString("data"), BoardVO.class);
        List<String> industrys = Lists.newArrayList();
        List<String> regions = Lists.newArrayList();
        List<String> subjectMatters = Lists.newArrayList();
        for(BoardVO vo : array){
            String bc = StringUtils.isBlank(vo.getBoardCode())?"":String.format("BK%s",StringUtils.leftPad(vo.getBoardCode(),4,"0"));
            String boardCode = StringUtils.defaultIfBlank(bc,vo.getNewBoardCode());
            String boardType = StringUtils.defaultIfBlank(vo.getBoardType(),"0");
            switch (boardType){
                case "行业":
                    industrys.add(boardCode);
                    break;
                case "板块":
                    regions.add(boardCode);
                    break;
                default:
                    subjectMatters.add(boardCode);
            }
        }
        if(dataType == 1){
            model.setIndustryBoardCodes(StockStringUtil.join(StrUtil.COMMA,industrys));
            model.setRegionBoardCodes(StockStringUtil.join(StrUtil.COMMA,regions));
            model.setSubjectMatter(StockStringUtil.join(StrUtil.COMMA,subjectMatters));
        }else{
            model.setConceptBoardCodes(StockStringUtil.join(StrUtil.COMMA,subjectMatters));
        }
    }

    @Override
    public List<StockInfoModel> scanStockByBoardFund(Integer lastDay){
        this.baseMapper.scanStockByBoardFund(lastDay);
        return this.baseMapper.getScanStockByDaily(DateUtil.formatDate(DateUtil.date()));
    }

    @Override
    public StockCoreInfoModel pullLatestStockInfo(String stockCode) {
        StockInfoModel stockInfo = this.getStockInfo(stockCode);
        if(Objects.isNull(stockInfo)){
            return null;
        }
        String secids = String.format("%s.%s",stockInfo.getMarkCode(),stockInfo.getStockCode());
        String url = StrUtil.format(ApiConstant.STOCK_MV_URL,secids);
        String result = HttpUtil.sendGet(url,"application/javascript", StockConstant.UTF8,6000L);
        if(StringUtils.isBlank(result)){
            return null;
        }
        JSONObject object = JSON.parseObject(result);
        FinanceDataVO dataVO = StockStringUtil.getObject(object.getString("data"), FinanceDataVO.class);
        StockCoreInfoModel coreModel = new StockCoreInfoModel();
        coreModel.setStockCode(stockCode);
        coreModel.setTradeDate(new Date());
        coreModel.setCapitalStock(new BigDecimal(dataVO.getF84()));
        coreModel.setTradeCapitalStock(new BigDecimal(dataVO.getF85()));
        BigDecimal f46 = new BigDecimal(dataVO.getF46()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setOpenPrice(f46);
        BigDecimal f60 = new BigDecimal(dataVO.getF60()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setPreClosePrice(f60);
        BigDecimal f45 = new BigDecimal(dataVO.getF45()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setLowerPrice(f45);
        BigDecimal f44 = new BigDecimal(dataVO.getF44()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setHighPrice(f44);
        BigDecimal f51 = new BigDecimal(dataVO.getF51()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setTallPrice(f51);
        BigDecimal f52 = new BigDecimal(dataVO.getF52()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setLowestPrice(f52);
        BigDecimal f168 = new BigDecimal(dataVO.getF168()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setExchangeRate(f168);
        BigDecimal f50 = new BigDecimal(dataVO.getF50()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setVolumePercent(f50);
        coreModel.setTradeVolume(new BigDecimal(dataVO.getF47()));
        coreModel.setTradeAmount(new BigDecimal(dataVO.getF48()));
        coreModel.setPbRate(new BigDecimal(dataVO.getF167()));
        coreModel.setOuterVolume(new BigDecimal(dataVO.getF49()));
        coreModel.setInnerVolume(new BigDecimal(dataVO.getF161()));
        coreModel.setMarkValue(new BigDecimal(dataVO.getF116()));
        coreModel.setTradeMv(new BigDecimal(dataVO.getF117()));
        BigDecimal f43 = new BigDecimal(dataVO.getF43()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setPrice(f43);
        BigDecimal f170 = new BigDecimal(dataVO.getF170()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setUpDownPercent(f170);
        BigDecimal f169 = new BigDecimal(dataVO.getF169()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UP);
        coreModel.setUpDownAmt(f169);
        coreModel.setUpdateTime(new Date());
        coreModel.setCreateTime(new Date());
        return coreModel;
    }
}
